package com.fast.develop.core.io.disk;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.fast.develop.core.io.Folder;
import com.fast.develop.core.io.ResourceManager;
import com.fast.develop.core.io.memory.MemoryFileSystem;
import com.fast.develop.core.io.memory.MemoryFolder;
import com.fast.develop.meta.base.resource.FileResource;
import com.fast.develop.meta.base.resource.MetaFileMultResource;
import com.fast.develop.meta.base.resource.MultResource;
import com.fast.develop.meta.base.resource.PathResource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * @author 莫寅
 * @createTime 2022-06-10 14:22
 * @desc：
 */
@Slf4j
public class DiskResourceManager implements ResourceManager {

    private MemoryFileSystem memoryFileSystem = null;

    private MultResource<PathResource> multResource;

    private String rootPath;

    public DiskResourceManager(String rootPath) {
        this.multResource = new MetaFileMultResource(rootPath);
        this.rootPath = rootPath;
        reload();
    }

    /**
     * 重新加载
     */
    @Override
    public void reload(){
        this.memoryFileSystem = new MemoryFileSystem();
        multResource.reload();
        Arrays.stream(multResource.getResources()).forEach(resource -> {
            String pathname = resource.getPath();
            String[] props = pathname.split(rootPath + StrUtil.SLASH);
            if(props.length > 1){
                try {
                    memoryFileSystem.write(props[1], IoUtil.readBytes(new FileInputStream(pathname)));

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }else{
                try {
                    memoryFileSystem.write(props[0], IoUtil.readBytes(new FileInputStream(pathname)));
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        });

        memoryFileSystem.mark();
    }

    @Override
    public void createFolder(String path) {
        MemoryFolder memoryFolder = new MemoryFolder(memoryFileSystem, path);
        memoryFileSystem.createFolder(memoryFolder);
        String markFile = getPath(path, ".mark");
        createFile(markFile);
        flush();
    }

    @Override
    public void createFile(String name) {
        write(name, new byte[]{});
        flush();
    }

    @Override
    public void createFile(String name, byte[] bytes) {
        write(name, bytes);
        flush();
    }

    @Override
    public String rename(String path, String newName) {
        String suffix = FileUtil.getSuffix(path);
        String fullPath = rootPath + StrUtil.SLASH + path;

        if(StrUtil.isNotBlank(suffix)){
            newName += StrUtil.DOT + suffix;
        }

        File file = FileUtil.rename(new File(fullPath), newName, true);

        reload();

        return file.getPath().replace(rootPath + StrUtil.SLASH, "");
    }

    @Override
    public Folder getRootFolder() {
        return memoryFileSystem.getRootFolder();
    }

    @Override
    public boolean isAvailable(String pResourceName) {
        return memoryFileSystem.isAvailable(pResourceName);
    }

    @Override
    public byte[] getBytes(String pResourceName) {
        return memoryFileSystem.getBytes(pResourceName);
    }

    @Override
    public Collection<String> getFileNames() {
        return memoryFileSystem.getFileNames();
    }

    @Override
    public Collection<String> getFolderNames() {
        return memoryFileSystem.getFolderNames();
    }


    @Override
    public Collection<String> getModifiedResourcesSinceLastMark() {
        return null;
    }

    @Override
    public void write(String pResourceName, byte[] pResourceData) {
        memoryFileSystem.write(pResourceName, pResourceData);

    }

    @Override
    public void write(String pResourceName, byte[] pResourceData, boolean createFolder) {
        memoryFileSystem.write(pResourceName, pResourceData, createFolder);

    }

    @Override
    public byte[] read(String pResourceName) {
        return memoryFileSystem.read(pResourceName);
    }

    @Override
    public void remove(String path) {
        //是否是文件夹
        if(memoryFileSystem.existsFolder(path)){
            Folder folder = new MemoryFolder(memoryFileSystem, path);
            memoryFileSystem.remove(folder);
            flush();
        }
        //是否是文件
        else if(memoryFileSystem.existsFile(path)){
            memoryFileSystem.remove(path);
            flush();
        }

    }

    private void flush(){
        memoryFileSystem.getModifiedResourcesSinceLastMark().stream().forEach(s -> flush(s));
        memoryFileSystem.mark();
    }

    private void flush(String path){

        String fullPath = getPath(this.rootPath, path);
        //是否是文件夹
        if(memoryFileSystem.existsFolder(path)){
            FileUtil.mkdir(fullPath);
            if(log.isDebugEnabled()){
                log.debug("将文件夹写入磁盘：{}", fullPath);
            }
        }
        //是否是文件
        else if(memoryFileSystem.existsFile(path)){
            byte[] bytes = memoryFileSystem.read(path);
            FileUtil.writeBytes(bytes, fullPath);
            if(log.isDebugEnabled()){
                log.debug("将文件写入磁盘：{}", fullPath);
            }
//            memoryFileSystem.writeAsFsByModifiedFilesSinceLastMark(new File(rootPath));
        }
        //都不存在则已删除
        else{
            if(log.isDebugEnabled()){
                log.debug("将文件删除磁盘：{}", fullPath);
            }
            FileUtil.del(fullPath);
        }

    }


    private String getPath(String path, String name){
        if(path.charAt(path.length()-1) != StrUtil.SLASH.charAt(0)){
            path += "/";
        }

        if(name.indexOf(StrUtil.SLASH) == 0){
            name = name.substring(1, name.length());
        }
        return path + name;
    }

}
